package com.kai.service.upload.facade;

import com.kai.service.data.dto.upload.SingleFileUploadDto;
import com.kai.service.data.dto.upload.UploadObjectDto;
import com.kai.service.data.request.upload.SingleFileUploadRequest;
import com.kai.service.data.request.upload.UploadTaskRequest;
import com.kai.service.data.dto.upload.UploadFileInfoDto;
import com.kai.service.data.response.upload.SingleFileUploadResponse;
import com.kai.service.data.response.upload.UploadTaskResponse;
import com.kai.service.exception.GenericException;
import com.kai.service.upload.entity.UploadTask;
import com.kai.service.upload.service.IUploadTaskService;
import com.kai.service.util.AmazonS3Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class UploadFacade {

    @Autowired
    private IUploadTaskService uploadTaskService;

    @Autowired
    private AmazonS3Util amazonS3Util;

    /**
     * 获取上传任务
     *
     * @param fileIdentifier 文件唯一标识（MD5）
     * @return
     */
    public UploadTaskResponse getUploadTask(String fileIdentifier) {
        UploadTask uploadTask = uploadTaskService.lambdaQuery().eq(UploadTask::getFileIdentifier, fileIdentifier).one();
        if (Objects.isNull(uploadTask)) {
            return null;
        }

        UploadTaskResponse response = new UploadTaskResponse()
                .setUrl(amazonS3Util.completeUrl(uploadTask.getBucketName(), uploadTask.getObjectKey()));

        // 查看文件是否存在
        Boolean doesObjectExist = amazonS3Util.doesObjectExist(uploadTask.getBucketName(), uploadTask.getObjectKey());
        if (doesObjectExist) {
            return response.setIsFinished(Boolean.TRUE);
        }

        // 未上传完，返回已上传的分片
        List<UploadFileInfoDto> uploadFileInfos = amazonS3Util.listParts(uploadTask.getUploadId(), uploadTask.getBucketName(), uploadTask.getObjectKey());
        return response.setIsFinished(Boolean.FALSE).setUploadFileInfos(uploadFileInfos);
    }

    /**
     * 创建分片上传任务
     *
     * @param request
     * @return
     */
    public String createMultipartUploadTask(UploadTaskRequest request) {
        UploadObjectDto uploadObject = amazonS3Util.initiateMultipartUpload(request.getFileName());
        BigDecimal chunkNum = BigDecimal.valueOf(request.getTotalSize()).divide(BigDecimal.valueOf(request.getChunkSize()), 0, RoundingMode.UP);

        UploadTask uploadTask = new UploadTask()
                .setUploadId(uploadObject.getUploadId())
                .setFileIdentifier(request.getFileIdentifier())
                .setFileName(request.getFileName())
                .setBucketName(uploadObject.getBucket())
                .setObjectKey(uploadObject.getObjectKey())
                .setTotalSize(request.getTotalSize())
                .setChunkSize(request.getChunkSize())
                .setChunkNum(Integer.valueOf(chunkNum.toString()))
                .setCreateDatetime(new Date());
        uploadTaskService.save(uploadTask);

        return amazonS3Util.completeUrl(uploadTask.getBucketName(), uploadTask.getObjectKey());
    }

    /**
     * 获取预签名上传url
     *
     * @param fileIdentifier 文件唯一标识（MD5）
     * @param partNumber 分片数
     * @return
     */
    public String getPreSignUploadUrl(String fileIdentifier, Integer partNumber) {
        UploadTask uploadTask = uploadTaskService.lambdaQuery().eq(UploadTask::getFileIdentifier, fileIdentifier).one();
        if (uploadTask == null) {
            throw new GenericException("上传任务不存在!");
        }

        return amazonS3Util.genPreSignUploadUrl(uploadTask.getUploadId(), uploadTask.getBucketName(), uploadTask.getObjectKey(), partNumber);
    }

    /**
     * 合并分片
     *
     * @param fileIdentifier 文件唯一标识（MD5）
     * @return
     */
    public Boolean mergePart(String fileIdentifier) {
        UploadTask uploadTask = uploadTaskService.lambdaQuery().eq(UploadTask::getFileIdentifier, fileIdentifier).one();
        if (uploadTask == null) {
            throw new GenericException("上传任务不存在!");
        }

        List<UploadFileInfoDto> uploadFileInfos = amazonS3Util.listParts(uploadTask.getUploadId(), uploadTask.getBucketName(), uploadTask.getObjectKey());
        if (uploadTask.getChunkNum() != uploadFileInfos.size()) {
            // 已上传分块数量与记录中的数量不对应，不能合并分块
            throw new GenericException("分片缺失，请重新上传!");
        }

        amazonS3Util.completeMultipartUpload(uploadTask.getUploadId(), uploadTask.getBucketName(), uploadTask.getObjectKey(), uploadFileInfos);
        return Boolean.TRUE;
    }

    /**
     * 单文件上传
     *
     * @param request
     * @return
     */
    public SingleFileUploadResponse singleFileUpload(SingleFileUploadRequest request) {
        UploadTask uploadTask = uploadTaskService.lambdaQuery().eq(UploadTask::getFileIdentifier, request.getFileIdentifier()).one();
        Boolean doesObjectExist = false;
        String objectKey = null;
        if (Objects.nonNull(uploadTask)) {
            objectKey = uploadTask.getObjectKey();
            doesObjectExist = amazonS3Util.doesObjectExist(uploadTask.getBucketName(), objectKey);
        }

        String presignedUrl = null;
        if (!doesObjectExist) {
            SingleFileUploadDto singleFileUploadDto = amazonS3Util.singleFileUpload(request.getFileName(), objectKey);
            presignedUrl = singleFileUploadDto.getPresignedUrl();

            if (Objects.isNull(uploadTask)) {
                uploadTask = new UploadTask()
                        .setFileIdentifier(request.getFileIdentifier())
                        .setFileName(request.getFileName())
                        .setBucketName(singleFileUploadDto.getBucket())
                        .setObjectKey(singleFileUploadDto.getObjectKey())
                        .setTotalSize(request.getTotalSize())
                        .setChunkSize(request.getTotalSize())
                        .setChunkNum(1)
                        .setCreateDatetime(new Date());
                uploadTaskService.save(uploadTask);
            }
        }

        return new SingleFileUploadResponse()
                .setUrl(amazonS3Util.completeUrl(uploadTask.getBucketName(), uploadTask.getObjectKey()))
                .setPreSignUploadUrl(presignedUrl);
    }
}
